package com.ebocy.hammer.world.resourceManage;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.ebocy.hammer.core.db.DaoManager;
import com.ebocy.hammer.core.db.IDao;
import com.ebocy.hammer.core.domain.Hammer;
import com.ebocy.hammer.core.domain.Item;
import com.ebocy.hammer.core.domain.Rank;
import com.ebocy.hammer.core.domain.Role;
import com.ebocy.hammer.core.domain.Shop;

@SuppressWarnings("unchecked")
public class XmlLoader {
	private static List<String> xmlFiles = new ArrayList<String>();
	private static IDao<Hammer> hammerDao = null;
	private static IDao<Item> itemDao = null;
	private static IDao<Role> roleDao = null;
	private static IDao<Shop> shopDao = null;
	private static IDao<Rank> rankDao = null;

	static {
		hammerDao = DaoManager.getInstance().getDao(Hammer.class);
		itemDao = DaoManager.getInstance().getDao(Item.class);
		roleDao = DaoManager.getInstance().getDao(Role.class);
		shopDao = DaoManager.getInstance().getDao(Shop.class);
		rankDao = DaoManager.getInstance().getDao(Rank.class);

		try {
			String url = XmlLoader.class.getResource("").getPath();
			boolean isInJar = false;
			if (url.indexOf(".jar") != -1) {
				isInJar = true;
			}
			if (isInJar) {
				loadMessageClassInJar(url);
			} else {
				loadMessageClassInFolder();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private static void loadMessageClassInJar(String url) throws IOException {
		String jarPath = url.substring("file:".length(), url.indexOf("!"));
		JarFile file = new JarFile(jarPath);
		Enumeration<JarEntry> files = file.entries();
		while (files.hasMoreElements()) {
			JarEntry entry = files.nextElement();
			String entryName = entry.getName();
			if (entryName.indexOf("xml/") != -1 && entryName.endsWith(".xml")) {
				xmlFiles.add(entryName.split("/")[1]);
			}
		}
	}

	private static void loadMessageClassInFolder() {
		String url = XmlLoader.class.getResource("/").getPath();
		File[] files = null;
		File tempFile = new File(url + "xml/");
		if (tempFile.isDirectory()) {
			files = new File(url + "xml/").listFiles();
			for (File file : files) {
				xmlFiles.add(file.getName());
			}
		}
	}

	/**
	 * 读取xml配置数据并更新DB
	 */
	public static void xmlInit() {
		// 获取锤子静态数据
		List<Object> hammerList = getObjectList(Hammer.class);
		for (Object obj : hammerList) {
			Hammer hammer = (Hammer) obj;
			hammerDao.delete("hammerId", hammer.getHammerId());
			hammerDao.insert((Hammer) hammer).getId();
		}

		// 获取物品静态信息
		List<Object> itemerList = getObjectList(Item.class);
		for (Object obj : itemerList) {
			Item item = (Item) obj;
			itemDao.delete("itemId", item.getItemId());
			itemDao.insert(item);
		}

		// 获取形象数据
		List<Object> roleList = getObjectList(Role.class);
		for (Object obj : roleList) {
			Role role = (Role) obj;
			roleDao.delete("roleId", role.getRoleId());
			roleDao.insert(role);
		}
		// 获取商店数据
		List<Object> shopList = getObjectList(Shop.class);
		for (Object obj : shopList) {
			Shop shop = (Shop) obj;
			shopDao.delete("waresId", shop.getWaresId());
			shopDao.insert(shop);
		}
		// 获取等级数据
		List<Object> rankList = getObjectList(Rank.class);
		for (Object obj : rankList) {
			Rank rank = (Rank) obj;
			rankDao.delete("rank", rank.getRank());
			rankDao.insert(rank);
		}

	}

	private static List<Object> getObjectList(Class<?> clazz) {
		List<Object> objectList = new ArrayList<Object>();
		try {
			String className = clazz.getSimpleName();
			Element root = getRootElement(className);
			for (Iterator ie = root.elementIterator(); ie.hasNext();) {
				Element element = (Element) ie.next();
				Object obj = clazz.newInstance();
				Field[] fields = obj.getClass().getDeclaredFields();
				int size = fields.length;
				// 枚举属性
				for (Iterator ia = element.attributeIterator(); ia.hasNext();) {
					Attribute attribute = (Attribute) ia.next();
					String attName = attribute.getName();
					Field field = null;
					Method setMethod = null;
					for (int i = 0; i < size; i++) {
						field = fields[i];
						String fieldName = field.getName();
						if (fieldName.equals(attName)) {
							String firstLetter = fieldName.substring(0, 1).toUpperCase();
							String setMethodName = "set" + firstLetter + fieldName.substring(1);
							setMethod = obj.getClass().getDeclaredMethod(setMethodName, field.getType());
							setMethod.invoke(obj, convert(attribute.getData(), field.getType()));
							break;
						}
					}
				}
				objectList.add(obj);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return objectList;
	}

	private static Element getRootElement(String fileName) throws Exception {
		return getDocument(fileName).getRootElement();
	}

	private static Document getDocument(String fileName) throws Exception {
		SAXReader saxReader = new SAXReader();
		Document document = null;
		for (String file : xmlFiles) {
			if (file.indexOf(fileName) != -1) {
				document = saxReader.read(XmlLoader.class.getResourceAsStream("/xml/" + file));
				break;
			}
		}
		return document;
	}

	private static Object convert(Object object, Class<?> type) {
		Number number = null;
		if (type.equals(String.class)) {
			return object;
		} else {
			number = Integer.valueOf(object.toString());
		}
		if (type.equals(byte.class) || type.equals(Byte.class)) {
			return number.byteValue();
		}
		if (type.equals(short.class) || type.equals(Short.class)) {
			return number.shortValue();
		}
		if (type.equals(int.class) || type.equals(Integer.class)) {
			return number.intValue();
		}
		if (type.equals(long.class) || type.equals(Long.class)) {
			return number.longValue();
		}
		if (type.equals(float.class) || type.equals(Float.class)) {
			return number.floatValue();
		}
		if (type.equals(double.class) || type.equals(Double.class)) {
			return number.doubleValue();
		}
		return object;
	}

}
